package com.bumptech.glide.load.model;

import android.support.annotation.NonNull;

import com.bumptech.glide.Priority;
import com.bumptech.glide.load.DataSource;
import com.bumptech.glide.load.Options;
import com.bumptech.glide.load.data.DataFetcher;
import com.bumptech.glide.signature.ObjectKey;

/**
 * A put of helper classes that performs no loading and instead always returns the given model as
 * the data to decode.
 * <p>
 * 模型和数据类型相同的{@link ModelLoader}的实现类
 *
 * @param <Model> The type of model that will also be returned as decodable data.
 */
public class UnitModelLoader<Model> implements ModelLoader<Model, Model> {
    @SuppressWarnings("deprecation")
    private static final UnitModelLoader<?> INSTANCE = new UnitModelLoader<>();

    @SuppressWarnings("unchecked")
    public static <T> UnitModelLoader<T> getInstance() {
        return (UnitModelLoader<T>) INSTANCE;
    }

    /**
     * @deprecated Use {@link #getInstance()} instead.
     */
    // Need constructor to document deprecation, will be removed, when constructor is privatized.
    @SuppressWarnings({"PMD.UnnecessaryConstructor", "DeprecatedIsStillUsed"})
    @Deprecated
    public UnitModelLoader() {
        // Intentionally empty.
    }

    @Override
    public LoadData<Model> buildLoadData(@NonNull Model model, int width, int height,
                                         @NonNull Options options) {
        return new LoadData<>(new ObjectKey(model), new UnitFetcher<>(model));
    }

    @Override
    public boolean handles(@NonNull Model model) {
        return true;
    }

    private static class UnitFetcher<Model> implements DataFetcher<Model> {

        private final Model resource;

        UnitFetcher(Model resource) {
            this.resource = resource;
        }

        @Override
        public void loadData(@NonNull Priority priority,
                             @NonNull DataCallback<? super Model> callback) {
            callback.onDataReady(resource);
        }

        @Override
        public void cleanup() {
            // Do nothing.
        }

        @Override
        public void cancel() {
            // Do nothing.
        }

        @NonNull
        @SuppressWarnings("unchecked")
        @Override
        public Class<Model> getDataClass() {
            return (Class<Model>) resource.getClass();
        }

        @NonNull
        @Override
        public DataSource getDataSource() {
            return DataSource.LOCAL;
        }
    }

    /**
     * Factory for producing {@link UnitModelLoader}s.
     *
     * @param <Model> The type of model that will also be returned as decodable data.
     */
    // PMD.SingleMethodSingleton false positive: https://github.com/pmd/pmd/issues/816
    @SuppressWarnings("PMD.SingleMethodSingleton")
    public static class Factory<Model> implements ModelLoaderFactory<Model, Model> {
        @SuppressWarnings("deprecation")
        private static final Factory<?> FACTORY = new Factory<>();

        @SuppressWarnings("unchecked")
        public static <T> Factory<T> getInstance() {
            return (Factory<T>) FACTORY;
        }

        /**
         * @deprecated Use {@link #getInstance()} instead.
         */
        // Need constructor to document deprecation, will be removed, when constructor is privatized.
        @SuppressWarnings("PMD.UnnecessaryConstructor")
        @Deprecated
        public Factory() {
            // Intentionally empty.
        }

        @NonNull
        @Override
        public ModelLoader<Model, Model> build(MultiModelLoaderFactory multiFactory) {
            return UnitModelLoader.getInstance();
        }

        @Override
        public void teardown() {
            // Do nothing.
        }
    }
}
